﻿#include "stdafx.h"
#include "sbcs.h"
#if __GNUC__
#include <wctype.h>
#endif
#include "PatrickPowell_snprintf.h"

#if _MSC_VER
#pragma warning(push)
#pragma warning(disable:4706)
#endif

//////////////////////////////////////////////////////////////////////////
// 유니코드 문자열 처리 

// MSC v13.10 - ctype.h
#define _k_iswalpha(c)					((L'A'<=(c) && (c)<=L'Z') || (L'a'<=(c) && (c)<=L'z'))
#define _k_iswdigit(c)					(L'0'<=(c) && (c)<=L'9')
#define _k_towlower(c)					((((c)>=L'A') && ((c)<=L'Z')) ? ((c)-L'A'+L'a') : (c))
#define _k_towupper(c)					((((c)>=L'a') && ((c)<=L'z')) ? ((c)-L'a'+L'A') : (c))


//
static void _wcs_output(kpointer ptr, size_t *currlen, size_t maxlen, int c)
{
	kwchar* buffer = (kwchar*)ptr;
	if (*currlen < maxlen)
		buffer[(*currlen)] = (kwchar)c;
	(*currlen)++;
}

//
static void _wcs_output_closure(kpointer ptr, size_t currlen, size_t maxlen)
{
	kwchar* buffer = (kwchar*)ptr;
	if (currlen < maxlen - 1)
		buffer[currlen] = L'\0';
	else if (maxlen > 0)
		buffer[maxlen - 1] = L'\0';
}

//
static void _wcs_file(kpointer ptr, size_t* currlen, size_t maxlen, int c)
{
	FILE* fp = (FILE*)ptr;
	fputwc((kwchar)c, fp);
	(*currlen)++;
}

// vsnprintf
kint k_vsnwprintf(kwchar* out, ksize_t len, const kwchar* fmt, va_list va)
{
	ksize_t res;

	k_return_value_if_fail(fmt != NULL, -1);

	res = doprw(_wcs_output, _wcs_output_closure, out, len, fmt, va);

	if (len)
		len--;

	return out ? (kint)K_MIN(res, len) : (kint)res;
}

// vaprintf
kint k_vaswprintf(kwchar** out, const kwchar* fmt, va_list va)
{
	ksize_t len;

	k_return_value_if_fail(out != NULL, -2);
	k_return_value_if_fail(fmt != NULL, -1);

	len = doprw(_wcs_output, _wcs_output_closure, NULL, 0, fmt, va);
	if (len <= 0)
	{
		*out = NULL;
		return 0;
	}

	*out = k_new(len + 1, kwchar);
	len = k_vsnwprintf(*out, len + 1, fmt, va);

	return (kint)len;
}

//
kwchar* k_vapswprintf(const kwchar* fmt, va_list va)
{
	ksize_t len;
	kwchar* ret;

	k_return_value_if_fail(fmt != NULL, NULL);

	len = doprw(_wcs_output, _wcs_output_closure, NULL, 0, fmt, va);
	if (len <= 0)
		return NULL;

	ret = k_new(len + 1, kwchar);
	k_vsnwprintf(ret, len + 1, fmt, va);

	return ret;
}

// vfprintf
kint k_vfwprintf(FILE* file, const kwchar* fmt, va_list va)
{
	// 32K까지 가능
	k_return_value_if_fail(fmt != NULL, -1);
	return (kint)doprw(_wcs_file, NULL, file, 1024 * 32, fmt, va);
}

// vprintf
kint k_vwprintf(const kwchar* fmt, va_list va)
{
	return k_vfwprintf(stdout, fmt, va);
}

// snprintf
kint k_snwprintf(kwchar* out, ksize_t len, const kwchar* fmt, ...)
{
	va_list va;
	kint ret;

	va_start(va, fmt);
	ret = k_vsnwprintf(out, len, fmt, va);
	va_end(va);

	return ret;
}

// asprintf
kint k_aswprintf(kwchar** out, const kwchar* fmt, ...)
{
	va_list va;
	kint ret;

	va_start(va, fmt);
	ret = k_vaswprintf(out, fmt, va);
	va_end(va);

	return ret;
}

//
kwchar* k_apswprintf(const kwchar* fmt, ...)
{
	va_list va;
	kwchar* ret;

	va_start(va, fmt);
	ret = k_vapswprintf(fmt, va);
	va_end(va);

	return ret;
}

// fprintf
kint k_fwprintf(FILE* file, const kwchar* fmt, ...)
{
	va_list va;
	kint ret;

	va_start(va, fmt);
	ret = k_vfwprintf(file, fmt, va);
	va_end(va);

	return ret;
}

// printf
kint k_wprintf(const kwchar* fmt, ...)
{
	va_list va;
	kint ret;

	va_start(va, fmt);
	ret = k_vwprintf(fmt, va);
	va_end(va);

	return ret;
}

// 해시
ksize_t k_wcshash(const kwchar* p)
{
	const kwchar* sz = p;
	ksize_t h = *sz++;
	if (!h)
		return 0;
	else
	{
		kint c;
		for (c = 0; *sz && c < 256; sz++, c++)
			h = (h << 5) - h + *sz;
		h = (h << 5) - h + c;
		return h;
	}
}

// 해시
ksize_t k_wcsihash(const kwchar* p)
{
	const kwchar* sz = p;
	ksize_t h = _k_towupper(*sz);
	if (!h)
		return 0;
	else
	{
		kint c;
		sz++;
		for (c = 0; *sz && c < 256; sz++, c++)
			h = (h << 5) - h + _k_towupper(*sz);
		h = (h << 5) - h + c;
		return h;
	}
}

// 길이
ksize_t k_wcslen(const kwchar* p)
{
	const kwchar* org = p;
	while (*p++);
	return p - org - 1;
}

// 복사
kwchar* k_wcscpy(kwchar* dest, const kwchar* src)
{
	kwchar* org = dest;
	while ((*dest++ = *src++));
	return org;
}

// 복사, 최종 위치 반환
kwchar* k_wcspcpy(kwchar* dest, const kwchar*  src)
{
	do (*dest++ = *src);
	while (*src++ != L'\0');
	return dest - 1;
}

// 길이 복사
kwchar* k_wcsncpy(kwchar* dest, const kwchar* src, ksize_t len)
{
	kwchar* org = dest;

	while (len && (*dest++ = *src++))
		--len;
	*dest = L'\0';

	if (len)
	{
		while (--len)
			*dest++ = L'\0';
	}

	return org;
}

// 더하기
kwchar* k_wcscat(kwchar* dest, const kwchar* src)
{
	kwchar* org = dest;
	while (*dest) ++dest;
	while ((*dest++ = *src++));
	return org;
}

// 길이 더하기
kwchar* k_wcsncat(kwchar* dest, ksize_t len, const kwchar* src)
{
	kwchar* org = dest;

	while (*dest++);
	--dest;

	while (len--)
	{
		if (!(*dest++ = *src++))
			return org;
	}

	*dest = L'\0';
	return org;
}

// 여럿 더하기
kwchar* k_wcsconcat(kwchar* dest, ...)
{
	va_list va;
	kwchar* c = dest;
	kwchar* s;

	while (*c++);
	--c;

	va_start(va, dest);
	s = va_arg(va, kwchar*);
	while (s)
	{
		c = k_wcspcpy(c, s);
		s = va_arg(va, kwchar*);
	}
	va_end(va);

	return dest;
}

// 복제
kwchar* k_wcsdup(const kwchar* p)
{
	kwchar* d;
	ksize_t len;

	len = k_wcslen(p) + 1;

	d = k_new(len, kwchar);
	k_wcscpy(d, p);

	return d;
}

// 길이 복제
kwchar* k_wcsndup(const kwchar* p, ksize_t len)
{
	kwchar* d;
	d = k_new(len + 1, kwchar);
	k_wcsncpy(d, p, len);
	return d;
}

// 여럿 복제
kwchar* k_wcsdupcat(const kwchar* p, ...)
{
	va_list va;
	kwchar* str;
	kwchar* s, *c;
	ksize_t size;

	size = k_wcslen(p) + 1;
	va_start(va, p);
	s = va_arg(va, kwchar*);
	while (s)
	{
		size += k_wcslen(s);
		s = va_arg(va, kwchar*);
	}
	va_end(va);

	str = k_new(size, kwchar);
	c = str;

	c = k_wcspcpy(c, p);
	va_start(va, p);
	s = va_arg(va, kwchar*);
	while (s)
	{
		c = k_wcspcpy(c, s);
		s = va_arg(va, kwchar*);
	}
	va_end(va);

	return str;
}

// 뒤집기
kwchar* k_wcsrev(kwchar* p)
{
	kwchar* s = p;
	kwchar* l = p;
	kwchar ch;

	while (*s++);
	s -= 2;

	while (l < s)
	{
		ch = *l;
		*l++ = *s;
		*s-- = ch;
	}

	return p;
}

// 대문자로
kwchar* k_wcsupr(kwchar* p)
{
	kwchar* s = p;

	for (; *s; ++s)
	{
		if ((*s >= L'a') && (*s <= L'z'))
			*s += (kwchar)(L'A' - L'a');
	}

	return p;
}

// 소문자로
kwchar* k_wcslwr(kwchar* p)
{
	kwchar* s = p;

	for (; *s; ++s)
	{
		if ((*s >= L'A') && (*s <= L'Z'))
			*s += (kwchar)(L'a' - L'A');
	}

	return p;
}

// 글자 위치
kwchar* k_wcschr(const kwchar* p, kint ch)
{
	while (*p && *p != (kwchar)ch) p++;
	return (*p == (kwchar)ch) ? (kwchar*)p : NULL;
}

// 글자 찾기
kwchar* k_wcsrchr(const kwchar* p, kint ch)
{
	kwchar* s = (kwchar*)p;
	while (*s++);
	while (--s != p && *s != (kwchar)ch);
	return (*s == (kwchar)ch) ? (kwchar*)s : NULL;
}

// 문장 위치
kwchar* k_wcsstr(const kwchar* p, const kwchar* s)
{
	kwchar* cp = (kwchar*)p;
	kwchar* s1, *s2;

	if (!*s)
		return (kwchar*)p;

	while (*cp)
	{
		s1 = cp;
		s2 = (kwchar*)s;

		while (*s1 && *s2 && !(*s1 - *s2))
			s1++, s2++;

		if (!*s2)
			return cp;

		cp++;
	}

	return NULL;
}

// 문장 위치
kwchar* k_wcsistr(const kwchar* p, const kwchar* s)
{
	kwchar* cp = (kwchar*)p;
	kwchar* s1, *s2;

	if (!*s)
		return (kwchar*)p;

	while (*cp)
	{
		s1 = cp;
		s2 = (kwchar*)s;

		while (*s1 && *s2 && !(_k_towupper(*s1) - _k_towupper(*s2)))
			s1++, s2++;

		if (!*s2)
			return cp;

		cp++;
	}

	return NULL;
}

// 문자열 찾기
kwchar* k_wcsrstr(const kwchar* p, const kwchar* s)
{
	kwchar* cp;
	ksize_t pl, sl, i;

	if (!*s)
		return (kwchar*)p;

	pl = k_wcslen(p);
	sl = k_wcslen(s);

	if (pl < sl)
		return NULL;

	cp = (kwchar*)p + pl - sl;
	while (cp >= p)
	{
		for (i = 0; i < sl; i++)
		{
			if (cp[i] != s[i])
				goto pos_next;
		}

		return cp;

pos_next:
		p--;
	}

	return NULL;
}

// 문장 브레이크
kwchar* k_wcsbrk(const kwchar* p, const kwchar* c)
{
	kwchar* t;
	while (*p)
	{
		for (t = (kwchar*)c; *t; t++)
		{
			if (*t == *p)
			{
				return (kwchar*)p;
			}
		}
		p++;
	}
	return NULL;
}

// 왼쪽
kwchar* k_wcsleft(kwchar* dest, const kwchar* src, ksize_t len)
{
	ksize_t size = k_wcslen(src);

	if (len > size)
		k_wcscpy(dest, src);
	else
	{
		k_wcsncpy(dest, src, len);
		*(dest + len) = L'\0';
	}

	return dest;
}

// 오른쪽
kwchar* k_wcsright(kwchar* dest, const kwchar* src, ksize_t len)
{
	ksize_t size = k_wcslen(src);

	if (len > size)
		k_wcscpy(dest, src);
	else
	{
		k_wcsncpy(dest, src + size - len, len);
		*(dest + len) = L'\0';
	}

	return dest;
}

// 가운데
kwchar* k_wcsmid(kwchar* dest, const kwchar* src, ksize_t pos, ksize_t len)
{
	ksize_t size = k_wcslen(src);

	if (pos > size)
		*dest = L'\0';
	else
	{
		k_wcsncpy(dest, src + pos, len);
		*(dest + len) = L'\0';
	}

	return dest;
}

// 왼쪽 공백
kwchar* k_wcsltrim(kwchar* dest)
{
	kwchar* s;
	for (s = dest; *s && iswspace(*s); s++);
	if (dest != s)
		memmove(dest, s, (k_wcslen(s) + 1)*sizeof(kwchar));
	return dest;
}

// 오른쪽 공백
kwchar* k_wcsrtrim(kwchar* dest)
{
	ksize_t len = k_wcslen(dest);
	while (len--)
	{
		if (!iswspace(dest[len]))
			break;
		dest[len] = L'\0';
	}
	return dest;
}

// 양쪽 공백
kwchar* k_wcstrim(kwchar* dest)
{
	return k_wcsrtrim(k_wcsltrim(dest));
}

// 목록 제거
kwchar* k_wcsrem(kwchar* p, const kwchar* rmlist)
{
	kwchar* p1 = p;
	kwchar* p2 = p;

	while (*p1)
	{
		const kwchar* ps = rmlist;
		kcham b = FALSE;

		while (*ps)
		{
			if (*p1 == *ps)
			{
				b = TRUE;
				break;
			}
			++ps;
		}

		if (!b)
		{
			*p2 = *p1;
			++p2;
		}

		++p1;
	}

	*p2 = L'\0';

	return p;
}

// 비교
kcham k_wcseqv(const kwchar* p1, const kwchar* p2)
{
	return (p1 == p2) ? TRUE : k_wcscmp(p1, p2) == 0;
}

// 대소 비교
kcham k_wcsieqv(const kwchar* p1, const kwchar* p2)
{
	return (p1 == p2) ? TRUE : k_wcsicmp(p1, p2) == 0;
}

// 비교
kint k_wcscmp(const kwchar* p1, const kwchar* p2)
{
	kint ret = 0;

	while (!(ret = (kint)(*p1 - *p2)) && *p2)
		++p1, ++p2;

	if (ret<0)		ret = -1;
	else if (ret>0)	ret = 1;

	return ret;
}

// 길이 비교
kint k_wcsncmp(const kwchar* p1, const kwchar* p2, ksize_t len)
{
	if (!len)
		return 0;

	while (--len && *p1 && *p1 == *p2)
		++p1, ++p2;

	return (kint)(*p1 - *p2);
}

// 대소 비교
kint k_wcsicmp(const kwchar* p1, const kwchar* p2)
{
	kwchar f, l;

	do
	{
		f = (kwchar)_k_towlower(*p1);
		l = (kwchar)_k_towlower(*p2);
		++p1;
		++p2;
	} while (f && (f == l));

	return (kint)(f - l);
}

// 대소 길이 비교
kint k_wcsnicmp(const kwchar* p1, const kwchar* p2, ksize_t len)
{
	kwchar f, l;

	while (len && *p1 && *p2)
	{
		--len;

		f = (kwchar)_k_towlower(*p1);
		l = (kwchar)_k_towlower(*p2);

		if (f != l) return (f - l);
		++p1;
		++p2;
	}

	return (len) ? (kint)(p1 - p2) : 0;
}

// 와일드 카드 비교
kint k_wcswcmatch(const kwchar* wild, const kwchar* string)
{
	// Written by Jack Handy - jakkhandy@hotmail.com
	// http://www.codeproject.com/Articles/1088/Wildcard-string-compare-globbing
	const kwchar *cp = NULL, *mp = NULL;

	while ((*string) && (*wild != L'*'))
	{
		if ((*wild != *string) && (*wild != L'?'))
			return 0;
		wild++;
		string++;
	}

	while (*string)
	{
		if (*wild == L'*')
		{
			if (!*++wild)
				return 1;
			mp = wild;
			cp = string + 1;
		}
		else if ((*wild == *string) || (*wild == L'?'))
		{
			wild++;
			string++;
		}
		else
		{
			wild = mp;
			string = cp++;
		}
	}

	while (*wild == L'*')
		wild++;

	return !*wild;
}

// 대소 와일드 카드 비교
kint k_wcsiwcmatch(const kwchar* wild, const kwchar* string)
{
	// Written by Jack Handy - jakkhandy@hotmail.com
	// http://www.codeproject.com/Articles/1088/Wildcard-string-compare-globbing
	const kwchar *cp = NULL, *mp = NULL;

	while ((*string) && (*wild != L'*'))
	{
		if ((_k_towupper(*wild) != _k_towupper(*string)) && (*wild != L'?'))
			return 0;
		wild++;
		string++;
	}

	while (*string)
	{
		if (*wild == L'*')
		{
			if (!*++wild)
				return 1;
			mp = wild;
			cp = string + 1;
		}
		else if ((_k_towupper(*wild) == _k_towupper(*string)) || (*wild == L'?'))
		{
			wild++;
			string++;
		}
		else
		{
			wild = mp;
			string = cp++;
		}
	}

	while (*wild == L'*')
		wild++;

	return !*wild;
}

// 찾기
kint k_wcsfind(const kwchar* src, const kwchar* find, ksize_t index)
{
	const kwchar* p = src + index;
	const kwchar* s1, *s2;

	while (*p)
	{
		s1 = p;
		s2 = find;

		while (*s1 && *s2 && !(*s1 - *s2))
		{
			++s1;
			++s2;
		}

		if (!*s2)
			return (kint)(src + index - p);
	}

	return -1;
}

// 숫자 인가
kint k_wcsisnum(const kwchar* s)
{
	kint ret = 0;
	kint dot = 0;
	for (; *s; ++s)
	{
		if (*s == L'+' || *s == L'-')
			continue;
		else if (!_k_iswdigit(*s))
		{
			if (*s != L'.')
			{
				ret = 0;		// 숫자아님
				break;
			}
			else
			{
				if (dot > 0)
				{
					ret = 1;	// 정수
					break;
				}
				else
				{
					ret = -1;	// 실수
					++dot;
				}
			}
		}
	}
	return ret;
}

// 정수로
kint k_wcstoi(const kwchar* p)
{
	kint value;
	kint ch;
	kint sign;

	while (*p == L' ' || *p == L'\n' || *p == L'\r' || *p == L'\t') ++p;

	ch = (kint)*p++;
	sign = ch;

	if (ch == '-' || ch == '+')
		ch = (kint)*p++;

	value = 0;
	while ((ch = (ch >= (kint)L'0' && ch <= (kint)L'9') ? ch - (kint)L'0' : -1) != -1)
	{
		value = 10 * value + ch;
		ch = (kint)*p++;
	}

	return (sign == L'-') ? -value : value;
}

// 롱으로
klong k_wcstol(const kwchar* p)
{
	klong value;
	kint ch;
	kint sign;

	while (*p == L' ' || *p == L'\n' || *p == L'\r' || *p == L'\t') ++p;

	ch = (kint)*p++;
	sign = ch;

	if (ch == L'-' || ch == L'+')
		ch = (kint)*p++;

	value = 0;
	while ((ch = (ch >= (kint)L'0' && ch <= (kint)L'9') ? ch - (kint)L'0' : -1) != -1)
	{
		value = 10 * value + ch;
		ch = (kint)*p++;
	}

	return (sign == L'-') ? -value : value;
}

// 실수로
float k_wcstof(const kwchar* p, kwchar** sret)
{
	return (float)k_wcstod(p, sret);
}

// 더블로
double k_wcstod(const kwchar* p, kwchar** sret)
{
	// code from DJGPP, Copyright (C) 1996 DJ Delorie

	double r = 0.0;	// result
	double d;		// scale
	kint e = 0;		// exponent
	kint sign = 1;		// +- 1.0
	kint esign = 1;
	kint i;
	kint flags = 0;

	while ((*p == L' ') || (*p == L'\t'))
		++p;

	if (*p == L'+')
		++p;
	else if (*p == L'-')
	{
		sign = -1;
		++p;
	}

	while ((*p >= L'0') && (*p <= L'9'))
	{
		flags |= 1;
		r *= 10.0;
		r += *p - L'0';
		++p;
	}

	if (*p == L'.')
	{
		d = 0.1L;
		++p;
		while ((*p >= L'0') && (*p <= L'9'))
		{
			flags |= 2;
			r += d*(*p - L'0');
			++p;
			d *= 0.1L;
		}
	}

	if (flags == 0)
	{
		if (sret) *sret = (kwchar*)p;
		return 0;
	}

	if ((*p == L'e') || (*p == L'E'))
	{
		++p;
		if (*p == L'+')
			++p;
		else if (*p == L'-')
		{
			++p;
			esign = -1;
		}
		if ((*p<L'0') || (*p>L'9'))
		{
			if (sret) *sret = (kwchar*)p;
			return r;
		}

		while ((*p >= L'0') && (*p <= L'9'))
		{
			e *= 10;
			e += *p - L'0';
			++p;
		}
	}

	if (esign < 0)
	for (i = 1; i <= e; ++i)
		r *= 0.1L;
	else
	for (i = 1; i <= e; ++i)
		r *= 10.0;

	if (sret) *sret = (kwchar*)p;
	return r*sign;
}

static const kint s_wcs_base[256] =
{
	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,	// 0~15
	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, // 16~31
	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, // 32~47
	0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, 255, 255, 255, 255, // 48~63
	255, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, // 64~79
	25, 26, 27, 28, 29, 30, 31, 255, 255, 255, 255, 255, 255, 255, 255, 255, // 80~95
	255, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, // 96~111
	25, 26, 27, 28, 29, 30, 31, 255, 255, 255, 255, 255, 255, 255, 255, 255, // 112~127

	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
};

// 진수 변환
kuint k_wcstoi_base(const kwchar* p, kint base)
{
	kuint v;
	kint ch;

	if (base<2 || base>32)
		return 0;

	v = 0;
	while (*p == L' ' || *p == L'\n' || *p == L'\r' || *p == L'\t')
		++p;

	ch = s_wcs_base[(*p++) & 0xFF];
	while (ch < base)
	{
		v = v*base + ch;
		ch = s_wcs_base[(*p++) & 0xFF];
	}

	return v;
}

// 진수 변환
kulong k_wcstol_base(const kwchar* p, kint base)
{
	kulong v;
	kint ch;

	if (base<2 || base>32)
		return 0;

	v = 0;
	while (*p == L' ' || *p == L'\n' || *p == L'\r' || *p == L'\t')
		++p;

	ch = s_wcs_base[(*p++) & 0xFF];
	while (ch < base)
	{
		v = v*base + ch;
		ch = s_wcs_base[(*p++) & 0xFF];
	}

	return v;
}

// 불 변환
kcham k_wcstob(const kwchar* p)
{
	return k_wcsieqv(p, L"1") || k_wcsieqv(p, L"TRUE") || k_wcsieqv(p, L"YES") || k_wcsieqv(p, L"CHAM") || k_wcsieqv(p, L"ON");
}

// 채우기
ksize_t k_wcsfll(kwchar* dest, ksize_t pos, ksize_t end, int ch)
{
	ksize_t i, cnt;
	if (pos >= end)
		return pos;
	cnt = end - pos;
	for (i = 0; i < cnt; i++)
		dest[pos + i] = (kwchar)ch;
	return pos + cnt;
}

// 공백 채우기
ksize_t k_wcsspace(kwchar* dest, ksize_t pos, ksize_t end)
{
	ksize_t i, cnt;
	if (pos >= end)
		return pos;
	cnt = end - pos;
	for (i = 0; i < cnt; i++)
		dest[pos + i] = L' ';
	return pos + cnt;
}

// 한줄 분석
ksize_t k_wcsline(const kwchar* text, kwchar* line, ksize_t* readsize, kcham removespace)
{
	const kwchar* pos;
	kwchar* dst;
	ksize_t len;

	if (!text)
		return 0;

	pos = text;
	dst = line;
	for (len = 0;; ++dst, ++pos, ++len)
	{
		if (*pos == L'\n' || *pos == L'\0')
		{
			++pos;
			++len;
			break;
		}
		*dst = *pos;
	}
	*dst = L'\0';

	if (readsize)
		*readsize = len;

	pos = line;
	len = 0;
	if (removespace)
	{
		for (; *pos; ++pos)
		{
			if (*pos == L'\n' || *pos == L'\r' || *pos == L' ' || *pos == L'\t')
				continue;
			else
			{
				*line = *pos;
				++line;
				++len;
			}
		}
	}
	else
	{
		for (; *pos; ++pos)
		{
			if (*pos == L'\n' || *pos == L'\r')
				continue;
			else
			{
				*line = *pos;
				++line;
				++len;
			}
		}
	}
	*line = L'\0';

	return len;
}

// 토큰
kwchar* k_wcstok(kwchar* string, const kwchar* control, kwchar** context)
{
	kwchar* token;
	const kwchar* ctl;

	k_return_value_if_fail(context != NULL, NULL);
	k_return_value_if_fail(string != NULL || *context != NULL, NULL);
	k_return_value_if_fail(control != NULL, NULL);

	if (!string)
		string = *context;

	while (*string)
	{
		for (ctl = control; *ctl && *ctl != *string; ctl++)
			;
		if (!*ctl)
			break;
		string++;
	}

	token = string;

	while (*string)
	{
		for (ctl = control; *ctl && *ctl != *string; ctl++)
			;
		if (*ctl)
		{
			*string++ = L'\0';
			break;
		}
		string++;
	}

	*context = string;

	return token == string ? NULL : token;
}

// 패스 분석
kcham k_wsplitpath(const kwchar* path, kwchar* drv, kint drv_len, kwchar* dir, kint dir_len, kwchar* filename, kint filename_len, kwchar* ext, kint ext_len)
{
	const kwchar* tmp;
	const kwchar* slash;
	const kwchar* dot;
	kcham drvset = FALSE;
	kint	len = 0;
	kint	n;

	if (drv && drv_len)
		drvset = TRUE;

	if (drvset)
	{
		n = 3 - 2;
		tmp = path;

		while (n > 0 && *tmp != 0)
		{
			--n;
			++tmp;
		}
		if (*tmp == L':')
		{
			k_wcsncpy(drv, path, 3 - 1);
			path = tmp + 1;
		}
		else
		{
			if (drv)
				*((kwchar*)drv) = L'\0';
		}
	}

	slash = NULL;
	dot = NULL;
	tmp = path;

	for (; *tmp != 0; ++tmp)
	{
		if (*tmp == L'/' || *tmp == L'\\')
			slash = tmp + 1;
		else if (*tmp == L'.')
			dot = tmp;
	}

	if (slash)
	{
		if (dir && dir_len)
		{
			len = (kint)(slash - (kwchar*)path);
			k_wcsncpy(dir, path, (dir_len > len) ? len : dir_len);
		}
		path = slash;
	}
	else
	{
		if (dir)
			*((kwchar*)dir) = L'\0';
	}

	if (dot && (dot >= (kwchar*)path))
	{
		if (filename && filename_len)
		{
			len = (kint)(dot - (kwchar*)path);
			k_wcsncpy(filename, path, (filename_len > len) ? len : filename_len);
		}

		if (ext && ext_len)
		{
			len = (kint)(tmp - dot);
			k_wcsncpy(ext, dot, (ext_len > len) ? len : ext_len);
		}
	}
	else
	{
		if (filename && filename_len)
		{
			len = (kint)(tmp - (kwchar*)path);
			k_wcsncpy(filename, path, (filename_len > len) ? len : filename_len);
		}

		if (ext)
			*((kwchar*)ext) = L'\0';
	}

	return TRUE;
}

// 패스 분석 짧게
kcham k_wdivpath(const kwchar* path, kwchar* dir, kint dir_len, kwchar* filename, kint filename_len)
{
	const kwchar* slash = NULL;
	const kwchar* tmp = path;
	kint len;

	for (; *tmp != 0; ++tmp)
	{
		if (*tmp == L'/' || *tmp == L'\\')
			slash = tmp + 1;
	}

	if (slash)
	{
		if (dir && dir_len)
		{
			len = (kint)(slash - (const kwchar*)path);
			k_wcsncpy(dir, path, (dir_len > len) ? len : dir_len);
		}
		path = slash;
	}
	else
	{
		if (dir)
			*((kwchar*)dir) = L'\0';
	}

	if (filename && filename_len)
	{
		len = (kint)(tmp - (const kwchar*)path);
		k_wcsncpy(filename, path, (filename_len > len) ? len : filename_len);
	}

	return TRUE;
}

// 라이센스 정보는 strnatcmp를 참조 

static kint _k_wcs_nat_cmp_right(kwchar const* a, kwchar const* b)
{
	kint bias = 0;

	for (;; a++, b++)
	{
		if (!_k_iswdigit(*a) && !_k_iswdigit(*b))
			return bias;
		else if (!_k_iswdigit(*a))
			return -1;
		else if (!_k_iswdigit(*b))
			return +1;
		else if (*a<*b)
		{
			if (!bias)
				bias = -1;
		}
		else if (*a>*b)
		{
			if (!bias)
				bias = +1;
		}
		else if (!*a && !*b)
			return bias;
	}

	//return 0;
}

static kint _k_wcs_nat_cmp_left(kwchar const* a, kwchar const* b)
{
	for (;; a++, b++)
	{
		if (!_k_iswdigit(*a) && !_k_iswdigit(*b))
			return 0;
		else if (!_k_iswdigit(*a))
			return -1;
		else if (!_k_iswdigit(*b))
			return +1;
		else if (*a<*b)
			return -1;
		else if (*a>*b)
			return +1;
	}

	//return 0;
}

static kint _k_wcs_nat_internal(kwchar const* a, kwchar const* b, kcham incase)
{
	kwchar ca, cb;
	kint ai, bi;
	kint frac, res;

	for (ai = bi = 0;;)
	{
		ca = a[ai];
		cb = b[bi];

		while (iswspace(ca))
			ca = a[++ai];

		while (iswspace(cb))
			cb = b[++bi];

		if (_k_iswdigit(ca) && _k_iswdigit(cb))
		{
			frac = (ca == L'0' || cb == L'0');

			if (frac)
			{
				res = _k_wcs_nat_cmp_left(a + ai, b + bi);
				if (res != 0)
					return res;
			}
			else
			{
				res = _k_wcs_nat_cmp_right(a + ai, b + bi);
				if (res != 0)
					return res;
			}
		}

		if (!ca && !cb)
			return 0;

		if (incase)
		{
			ca = _k_towupper(ca);
			cb = _k_towupper(cb);
		}

		if (ca<cb)
			return -1;
		else if (ca>cb)
			return +1;

		++ai;
		++bi;
	}
}

// nat cmp
kint k_wcsnatcmp(const kwchar* left, const kwchar* right)
{
	return _k_wcs_nat_internal(left, right, FALSE);
}

// nat cmp
kint k_wcsnatcasecmp(const kwchar* left, const kwchar* right)
{
	return _k_wcs_nat_internal(left, right, TRUE);
}

#if _MSC_VER
#pragma warning(pop)
#endif
